/**
 * Project - The Three Phase Commit Protocol
 * Authors - Namrata Baliga, Aditya Joshi
 **/
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException; 
import java.io.PrintWriter;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.StringTokenizer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.Future;
import java.net.SocketTimeoutException;
import java.net.Socket;
import java.net.ServerSocket;
import java.util.concurrent.ExecutionException;


// The Participant class encompasses the coordinator
// and participant roles.
class Participant
{
    int port,pid;
    String logFile;
    // ArrayList of processes a node believes to be operational
    ArrayList<Integer> upSet;
    //Current state of the process. Commit/Abort/Uncertain
    String currentState;
    // the state request response
    String stateReqResp;
    // socket listening to incoming connections
    ServerSocket pSocket;
    // keeping track of number of responses got
    int allResp;
    // semaphore signifies threads waiting for all responses to come to awaken 
    boolean done;
    // number of participants in the protocol
    int numParticipants; 
    

    // Creating a new node

    public Participant(int pid, int port)
    {
        this.pid = pid;
        this.port = port;
        // 0 to indicate responses not got from all
        this.allResp=0;
        // false  that we r not doen yet
        this.done = false;
        this.numParticipants = 0;
        // Log file to hold protocol state in stable storage
        // Structure: state;upset. eg: ABORT;1:2000,2:3000
        this.logFile = ""+pid+".log";
        this.upSet = new ArrayList<Integer>();
       
        this.currentState = Const.START;
        this.stateReqResp = "";
        System.out.println("PID: "+pid+" - Created new node at port: "+port);
    }

    // reading the log at recovery
    public void readLog()
    {
        System.out.println("DEBUG: "+pid+" - Reading log information ");
        try
        {
            // Initialize upset to 0's. At time of recovery the upSet volatile
            // information is lost.
            for (int j=0;j<10;j++)
            {
                upSet.add(0);
            }
            BufferedReader br = new BufferedReader(new FileReader(logFile));
            String lastLine="",line="";
            // Go till the last "not null" line of the logfile
            do
            {
                lastLine = line;
                line = br.readLine();
            }while (line!=null);
            System.out.println("DEBUG: "+pid+" - last log line"+lastLine);
            // The logfile splitter
            StringTokenizer logTokens = new StringTokenizer(lastLine, ";");
            // updating the state
            currentState = logTokens.nextToken();
            System.out.println("DEBUG: "+pid+" - state from log file"+currentState);
            // getting the upset
            StringTokenizer upSetTokens =  new StringTokenizer(logTokens.nextToken(), ",");
            while (upSetTokens.hasMoreTokens())
            {
                StringTokenizer pidPort = new StringTokenizer(upSetTokens.nextToken(), ":");
                upSet.set(Integer.parseInt(pidPort.nextToken()),
                        Integer.parseInt(pidPort.nextToken()));
            }
            System.out.println("DEBUG: "+pid+" - Done reading log information ");
        }
        catch(IOException io)
        {
            System.out.println("PID: "+pid+" - Caught io exception: "+io.getMessage());
        }

    }

    public String upSetListToString()
    {
        Integer upSetArr [] =  upSet.toArray(new Integer [upSet.size ()]);
        String upSetConcat="";
        // creating a upSet string that is comma separated
        // concatenation of all pid:port pairs
        for (int i=0;i<upSetArr.length;i++)
        {
            if (upSetArr[i]!=0)
            {
                if (upSetConcat.equals(""))
                {
                    upSetConcat+=i+":"+upSetArr[i];
                }
                else
                {
                    upSetConcat+=","+i+":"+upSetArr[i];
                }
            }    
        }
        return upSetConcat;
    }

    public void upSetStrToList(String upSetStr)
    {
        System.out.println("got: "+upSetStr);
        StringTokenizer upSetTokens =  new StringTokenizer(upSetStr, ",");
        while (upSetTokens.hasMoreTokens())
        {
            StringTokenizer pidPort = new StringTokenizer(upSetTokens.nextToken(), ":");
            synchronized(this)
            {
                upSet.set(Integer.parseInt(pidPort.nextToken()),
                    Integer.parseInt(pidPort.nextToken()));
            }
        }
    }
    // Writing to the log. Synchronized to handle threads
    public synchronized void writeLog(String state,ArrayList<Integer> upSet)
    {
        try
        {
            // Writing to a log file
            BufferedWriter bw = new BufferedWriter(new FileWriter(logFile,true));
            
            // write to file
            bw.write(state+";"+upSetListToString());
            bw.newLine();
            bw.flush();
            bw.close();
            System.out.println("PID: "+pid+" - Wrote to log: "+state+";"+upSetListToString());
        }
        catch(IOException io)
        {
            System.out.println("PID: "+pid+" - Caught io: "+io.getMessage());
        }
    }

    public void invokeParticipant(String stage) throws SocketTimeoutException, IOException, InterruptedException, 
           ExecutionException
    {
        // Invoke participant logic
        pSocket=null;
        ExecutorService threadExecutor = null;
        int retVal = 0;
        System.out.println("DEBUG: "+pid+" - invoking participant code"); 
        try
        {
            // Open sockect to listen for incoming requests
            pSocket = new ServerSocket(this.port);
            //threadExecutor = Executors.newSingleThreadExecutor();
            threadExecutor = Executors.newFixedThreadPool(10);
       }
        catch(IOException io)
        {
            System.out.println("PID: "+pid
                    +" - Caught exception in sockect creation at port: "+this.port+". "+io.getMessage());
        }
        Set<Future<Integer>> set = new HashSet<Future<Integer>>();
        for (int i=0;i<Const.MAX_PARTICIPANTS;i++)
        {
            // Submit a participant thread. 
            FutureTask<Integer> task = new FutureTask<Integer> 
                (new ThreadParticipant(this, pSocket.accept(),stage));
            set.add(task);
            threadExecutor.submit(task);
        }
        try
        {
             for (Future<Integer> task : set)
             {
                 retVal = task.get();
             }
                
        }
        catch(InterruptedException io)
        {
        }
        catch(ExecutionException io)
        {
        }   
        System.out.println("DEBUG: "+pid+" val ret: "+retVal);
    }

    public int initiateElection()
    {
        int i=0, min_pid=pid, decision=0;
        while(i<upSet.size())
        {
            if(upSet.get(i)!=0 && i<min_pid)
                min_pid=i;
            i++;
        }
        if(min_pid==pid)
        {
            System.out.println("I am new co-ordinator");
            decision = Const.IM_COORD;
            //initiate terminataion protocol as co-ordinator
            
        }
        else
        {
            System.out.println("Process "+min_pid+" is the new co-ordinator");
             PrintWriter out = null;
                BufferedReader in = null;
            try
            {
                Socket pSocket = new Socket("localhost",upSet.get(min_pid));
                out = new PrintWriter(pSocket.getOutputStream(), true);
                in = new BufferedReader(new InputStreamReader(pSocket.getInputStream()));
                
            }
          
            catch (IOException e)
            {
                System.err.println("Couldn't get I/O for " + "the connection to: taranis.");
                System.exit(1);
            }

            System.out.println("connection to new coord succeeded");
         
            //remove all lower processes from upSet
        
            out.println("UR ELECTED");
            //participate in termination as participant
            decision = Const.IM_PARTICIPANT;
        }
        int j=0;
        while(j<min_pid)
        {
            upSet.set(j, 0);
            j++;
        }
        return decision;
    }


    public void invokeCoordinator(String stage)
    {
        // Coordinator action
        // Proactively connect to all participants
        System.out.println("PID:"+pid+" - Started coordinator mode");
        writeLog(stage,upSet);
        ThreadCoordinator[] tc = new ThreadCoordinator[10];
        ExecutorService threadExecutor = null;
        threadExecutor = Executors.newFixedThreadPool(10);
        //threadExecutor = Executors.newSingleThreadExecutor;
        Set<Future<Integer>> set = new HashSet<Future<Integer>>();
        for (int i = 0;i<upSet.size();i++)
        {
            System.out.println("Invoked for node: "+i+" upSet:"+upSet.get(i));
            if (upSet.get(i)!=0)
            {
                numParticipants++;
                FutureTask<Integer> task = new FutureTask<Integer> 
                    (new ThreadCoordinator(this,i,upSet.get(i),stage));
                System.out.println("Invoked for node: "+i);
                set.add(task);
                threadExecutor.submit(task);
            }   
        }
        int retVal =0;
        try
        {
             for (Future<Integer> task : set)
             {
                 retVal = task.get();
             }
        }
        catch(InterruptedException io)
        {
            System.out.println("Caught: ");
            io.printStackTrace();
        }
        catch(ExecutionException io)
        {
            System.out.println("Caught:");
            io.printStackTrace();
        }   
    }

    public void recover()
    {
        System.out.println("PID: "+pid+" - Recovering from crash ");
        // recover from log file
        readLog();       
        // reach a decision
        terminate();
    }

    public void terminate()
    {
        System.out.println("PID: "+pid+" - Initiating the termination protocol");
    }

    public void cleanUp()
    {
        System.out.println("PID: "+pid+" - Cleaning up process information");
        File f = new File(logFile);
        if (f.exists())
        {
            f.delete();
        }
        System.out.println("PID: "+pid+" - Clean up complete");
    }
}

class ThreadParticipant implements Callable 
{
    public int pid;
    public int port;
    public Socket cSocket;
    public Participant node;
    public String stage;
    public ThreadParticipant(Participant node, Socket cSocket, String stage)
    {
        //this.pid = pid;
        //this.port = port;
        this.node = node;
        this.cSocket = cSocket;
        this.stage = stage;
    }

    public Integer call() throws SocketTimeoutException, IOException, InterruptedException, ExecutionException
    {
        // Participant waits for coordinator
        System.out.println("PID: "+node.pid+" - New incoming connection");
        String readData = "";
        // Set i/o streams
        PrintWriter out = new PrintWriter(cSocket.getOutputStream(), true);
        BufferedReader in = new BufferedReader(new InputStreamReader(
                    cSocket.getInputStream()));
        // read response
        cSocket.setSoTimeout(Const.TIMEOUT); 
        if (stage.equals(Const.VOTE_REQ))
        {
            readData = in.readLine();
            System.out.println("PID: "+node.pid+" - Obtained "+readData);
            if (readData.indexOf(Const.VOTE_REQ) != -1)
            {
                StringTokenizer upSetTokens = new StringTokenizer(readData,";");
                upSetTokens.nextToken(); 
                node.upSetStrToList(upSetTokens.nextToken());
                node.writeLog(Const.VOTE_REQ,node.upSet);               
                Scanner stdin = new Scanner(System.in);
                System.out.print("PID: "+node.pid+" - Enter Vote (yes/no): ");
                String vote = stdin.nextLine();
                System.out.print("PID: "+node.pid+" - Sent Vote "+vote+" to coordinator");
                out.println(vote.toUpperCase());             
                if (vote.compareToIgnoreCase("YES") == 0)
                {
                    System.out.println("PID: "+node.pid+" - Waiting for ABORT or PRECOMMIT ");
                    readData = in.readLine();
                    System.out.println("GOT: "+readData);
                    if (readData.equals(Const.ABORT))
                    {
                        node.writeLog(Const.ABORT,node.upSet); 
                    }
                    else
                    {
                        out.println(Const.ACK);
                        readData = in.readLine();
                        node.writeLog(Const.COMMIT,node.upSet);
                    }
                }
                else
                {
                    System.out.println("PID: "+node.pid+" - Initiating ABORT sequence");
                    node.writeLog(Const.ABORT,node.upSet);
                }
            }
        }
        else if (stage.equals(Const.STATE_REQ))
        {
            // waiting for state request
            readData = in.readLine();
            if (node.currentState.equals(Const.COMMIT))
            {
                out.println(Const.COMMITTED); 
            }
            else if(node.currentState.equals(Const.PRE_COMMIT))
            {

            }
            else
            {

            }
            readData = in.readLine();
            if (readData.equals(Const.ABORT))
            {
                node.writeLog(Const.ABORT,null);

            }
            else if (readData.equals(Const.COMMIT))
            {
                node.writeLog(Const.COMMIT,null);
            }
            else
            {
                out.println(Const.ACK);
                readData = in.readLine();
                node.writeLog(Const.COMMIT,null);
            }
        }
        else if (readData.equals(Const.UR_ELECTED))
        {
            throw new ExecutionException(Const.UR_ELECTED,null);
        }
        System.out.println("This has to print");

        return 1;
    }
}

class ThreadCoordinator implements Callable 
{
    public int pid;
    public int port;
    public Participant node;
    public String stage;
    public ThreadCoordinator(Participant node, int pid, int port, String stage)
    {
        this.pid = pid;
        this.port = port;
        this.node = node;
        this.stage = stage;
    }
    
    public void incrementcurrNumResp(String resp)
    {
        synchronized (this.node)
        {
            this.node.allResp++;
            if (resp.equals(Const.VOTE_NO) || resp.equals(Const.REQ_TIMEOUT))
            {
                this.node.currentState = resp;
            }
            if (this.node.allResp == this.node.numParticipants)
            {
                this.node.done = true;
                this.node.allResp = 0;
                this.node.notifyAll();
            }
        }
    }

    public Integer call() throws Exception
    {
        String sent="",recv="";
        System.out.println("PID: "+this.node.pid+" - Connecting to process: "+this.pid);
        // connecting to participant
        Socket cSocket = new Socket("localhost",this.port);
        System.out.println("PID: "+this.node.pid+" - Connected to process: "+this.pid);
        cSocket.setSoTimeout(Const.TIMEOUT);
        //setting in/out buffers
        PrintWriter out = new PrintWriter(cSocket.getOutputStream(), true);
        BufferedReader in = new BufferedReader(new InputStreamReader(
                                           cSocket.getInputStream()));
        
        if (this.stage.equals(Const.VOTE_REQ))
        {
            System.out.println("PID: "+this.node.pid+" - Sending vote request to all participants");
            out.println(Const.VOTE_REQ+";"+this.node.upSetListToString());
            // waiting for VOTE_REQ response
            try
            {
                recv = in.readLine();
                System.out.println("PID:"+this.node.pid+" - Got response "+recv 
                    +"from participant: "+this.pid);
            }
            catch(SocketTimeoutException st)
            {
                System.out.println("PID: "+this.node.pid+" - Timedout from process: "+this.pid);
                recv = Const.REQ_TIMEOUT; 
            }
            if (recv == null)
            {
                System.out.println("PID: "+this.node.pid+" - Failure of process: "+this.pid);
                recv = Const.REQ_TIMEOUT;
            }
            incrementcurrNumResp(recv);
            synchronized (this.node)
            {
                while (!this.node.done)
                {   
                    try
                    {
                        this.node.wait();
                    }
                    catch(InterruptedException ie)
                    {
                    }
                }
            }
            System.out.println("state:"+this.node.currentState);
            if (this.node.currentState.indexOf(Const.REQ_TIMEOUT) != -1 || 
                 this.node.currentState.indexOf(Const.VOTE_NO) != -1  )
            {
                // somebody sent a no or timedout
                System.out.println("PID: "+this.node.pid+" Got "+this.node.currentState+" so aborting run."
                        +"Sending ABORT to all processes");
                this.node.writeLog("ABORT",null);
                out.println(Const.ABORT);
            }
            else
            {
                // all nodes sent a yes
                System.out.println("PID: "+this.node.pid+" - Sending PRECOMMIT");
                System.out.println("PID: "+this.node.pid+" - Waiting for ACK");
                synchronized (this)
                {
                    this.node.currentState = Const.PRE_COMMIT;
                }
                this.node.writeLog(Const.PRE_COMMIT,this.node.upSet);
                out.println(Const.PRE_COMMIT);
                try
                {
                    recv = in.readLine();
                    System.out.println("PID:"+this.node.pid+" - Got response "+recv 
                    +" from participant: "+this.pid);
                    System.out.println("PID:"+this.node.pid+" - Sending"+Const.COMMIT+" response "  
                    +" to participant: "+this.pid);
                    this.node.writeLog(Const.COMMIT, this.node.upSet);
                    out.println(Const.COMMIT);
                }
                catch (SocketTimeoutException st)
                {
                    System.out.println("PID: "+this.node.pid+" - Timedout from process: "+this.pid+
                            " Ignoring process failure");
                    synchronized (this)
                    {
                        this.node.upSet.set(this.pid, 0);
                        this.node.writeLog(Const.PRE_COMMIT,this.node.upSet);
                    }
                }
            }
        }
        else
        {
            // state request
            System.out.println("PID: "+this.node.pid+" - Sending state request to all participants");
            out.println(Const.STATE_REQ+";"+this.node.upSetListToString());
            // waiting for STATE_REQ response
            if (this.node.currentState.equals(Const.ABORT) || 
                    this.node.stateReqResp.equals(Const.ABORT) )
            {
                this.node.writeLog(Const.ABORT,null);
                out.println(Const.ABORT);
            }
            else if (this.node.currentState.equals(Const.COMMIT) || 
                    this.node.stateReqResp.equals(Const.COMMIT) )
            {
                this.node.writeLog(Const.COMMIT,null);
                out.println(Const.COMMIT);
            }
            else if (this.node.currentState.equals(Const.UNCERTAIN) || 
                    this.node.stateReqResp.equals(Const.UNCERTAIN) )
            {
                this.node.writeLog(Const.ABORT,null);
                out.println(Const.ABORT);
            }
            else
            {
                if (this.node.stateReqResp.equals(Const.UNCERTAIN) )
                {

                }
                this.node.writeLog(Const.COMMIT,null);
                out.println(Const.COMMIT);
            }

            try
            {
                recv = in.readLine();
                System.out.println("PID:"+this.node.pid+" - Got response "+recv 
                    +"from participant: "+this.pid);
            }
            catch(SocketTimeoutException st)
            {
                System.out.println("PID: "+this.node.pid+" - Timedout from process: "+this.pid);
                recv = Const.REQ_TIMEOUT; 
            }
            incrementcurrNumResp(recv);
            System.out.println("node done: "+this.node.done);
            while (this.node.done != true)
            {   
                try
                {
                    System.out.println("got stuck??");
                    synchronized (this)
                    {
                        wait();
                    }
                }
                catch(InterruptedException ie)
                {
                    System.out.println("awaken");

                }
            }
            this.node.done = false;
            if (this.node.currentState.indexOf(Const.VOTE_YES) == -1)
            {
                // somebody sent a no or timedout
                System.out.println("Aborting run. Sending ABORT to all processes");
                this.node.writeLog("ABORT",null);
                out.println(Const.ABORT);
            }
            else
            {
                // all nodes sent a yes
                System.out.println("PID: "+this.node.pid+" - Sending PRECOMMIT");
                System.out.println("PID: "+this.node.pid+" - Waiting for ACK");
                this.node.writeLog(Const.PRE_COMMIT,this.node.upSet);
                out.println(Const.PRE_COMMIT);
                try
                {
                    recv = in.readLine();
                    System.out.println("PID:"+this.node.pid+" - Got response "+recv 
                    +" from participant: "+this.pid);
                    System.out.println("PID:"+this.node.pid+" - Sending"+Const.COMMIT+" response "  
                    +" to participant: "+this.pid);
                    this.node.writeLog(Const.COMMIT, this.node.upSet);
                    out.println(Const.COMMIT);
                }
                catch (SocketTimeoutException st)
                {
                    System.out.println("PID: "+this.node.pid+" - Timedout from process: "+this.pid+
                            " Ignoring process failure");
                    synchronized (this)
                    {
                        this.node.upSet.set(this.pid, 0);
                        this.node.writeLog(Const.PRE_COMMIT,this.node.upSet);
                    }
                }
            }
       }
        return 0;
    }
}

class ThreePhaseCommit
{
    public static boolean isRecovering(String pid)
    {
        // Find out if the process is newly created or recovering
        boolean recover=false;
        File f = new File(pid+".log");
        if(f.exists())
            recover=true;
        return recover;
    }

    public static void main(String[] args)
    {
        System.out.println("-----Three Phase Commit Protocol-----");
        // Obtain the id and port of the process
        StringTokenizer idPort = new StringTokenizer(args[0], ":");
        String pid = idPort.nextToken(); 
        // participant or coordinator mode
        int mode = -1;
        // stage in which coordinator or participant is in
        String stage = "";
        // creating the first node
        Participant node = new Participant(Integer.parseInt(pid),Integer.parseInt(idPort.nextToken())); 
         // if exists DT log. recover from there.
        if (isRecovering(pid))
        {
            System.out.println("PID: "+pid+" - Recovering  from crash");
            //node.recover();
        }
        if (mode == -1)
        {
            System.out.println("3PC: Initialization Phase");
            if (pid.equals("0"))
            {
                //Coordinator node
                // Obtain set of hosts from host port pairs
                System.out.println("PID: "+pid+" - Initializing Coordinator node");
                // initialize a 10 elelment arraylist with port '0'
                ArrayList<Integer> otherHosts = new ArrayList<Integer>();
                for (int j=0;j<Const.MAX_PARTICIPANTS;j++)
                {
                    otherHosts.add(Const.DEAD_HOST);
                }
                // Parse arguments to obtain other nodes
                for (int i=1;i<args.length;i++)
                {
                    StringTokenizer otherIdPort = new StringTokenizer(args[i], ":");
                    String oPid = otherIdPort.nextToken();
                    otherHosts.set(Integer.parseInt(oPid),Integer.parseInt(otherIdPort.nextToken()));
                    System.out.println("PID: "+pid+" - Participant PID:"
                            +otherHosts.get(Integer.parseInt(oPid))+ " added");
                }
                // invoke coordinator mode
                mode = Const.IM_COORD;
                // Add nodes to the upset of coordinator
                node.upSet.addAll(otherHosts);
            }
            else
            {
                // participant mode
                System.out.println("PID: "+pid+" - Initializing Participant node");
                mode = Const.IM_PARTICIPANT;
                for (int j=0;j<Const.MAX_PARTICIPANTS;j++)
                {
                    node.upSet.add(0);
                }
            }
            // Coordinator to send VOTE_REQ and participant to wait for it
            stage = Const.VOTE_REQ;
        }
        // keep doing till killed or read end of algorithm
        boolean protoComplete = false;
        while (true)
        {
            try
            {
                if (mode == Const.IM_COORD && !protoComplete)
                {
                    System.out.println("PID: "+node.pid+" - Invoking Coordinator node");
                    node.invokeCoordinator(stage);
                    System.out.println("PID: "+node.pid+" - 3PC Successfully completed");
                }
                else if (mode == Const.IM_PARTICIPANT && !protoComplete)
                {
                     // The participant node
                    System.out.println("PID: "+node.pid+" - Invoking Participant node");
                    node.invokeParticipant(stage);
                    System.out.println("PID: "+node.pid+" - 3PC Successfully completed");
                }
                protoComplete = true;
            }
            catch(ExecutionException re)
            {
                System.out.println("DEBUG: "+node.pid+" - Caught io: " +re.getMessage());
                if ((re.getMessage()).indexOf(Const.UR_ELECTED) != -1)
                {
                    System.out.println("PID: "+node.pid+" GOT"+Const.UR_ELECTED+" message.");
                    // Coordinator has died and participant is new coordinator
                     stage  = Const.STATE_REQ;
                     mode = Const.IM_COORD;  
                }
            }
            catch(InterruptedException re)
            {
                System.out.println("PID: "+node.pid+" Caught io: "+re.getMessage());
            }
            catch(SocketTimeoutException st)
            {
                System.out.println("DEBUG: "+node.pid+st.getMessage());
                if (node.currentState.equals(Const.START))  
                {
                    System.out.println("PID: "+node.pid+" Timeout on Coordinator before "
                            +Const.VOTE_REQ+" was obtained. ABORTING");
                    node.writeLog(Const.ABORT,null);
                }
                else
                {
                    System.out.println("PID: "+node.pid+" Coordinator crashed. "
                            +" Initiating Election Protocol.");
                    mode = node.initiateElection();
                    stage  = Const.STATE_REQ;
                }
            }
            catch(IOException io)
            {
                System.out.println("Caught: "+io.getMessage());
                if (node.currentState.equals(Const.START))  
                {
                    System.out.println("PID: "+node.pid+" Coordinator crashed before "
                            +Const.VOTE_REQ+" was obtained. ABORTING");
                    node.writeLog(Const.ABORT,null);
                }
                else
                {
                    System.out.println("PID: "+node.pid+" Coordinator crashed. "
                            +" Initiating Election Protocol.");
                    mode = node.initiateElection();
                    stage  = Const.STATE_REQ;
                }
            }
        }
    }
}
